﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using NodaTime.Calendars;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Esst.Common
{
    internal class BrowserHelper
    {
    }

    public sealed class BrowserDetector : IBrowserDetector
    {
        private readonly Lazy<IBrowser> browser;

        private readonly IHttpContextAccessor httpContextAccessor;

        public IBrowser Browser => browser.Value;

        public BrowserDetector(IHttpContextAccessor httpContextAccessor)
        {
            this.httpContextAccessor = httpContextAccessor;
            browser = GetBrowserLazy();
        }

        private Lazy<IBrowser> GetBrowserLazy()
        {
            return new Lazy<IBrowser>(() => GetBrowser());
        }

        private IBrowser? GetBrowser()
        {
            HttpContext? httpContext = httpContextAccessor.HttpContext;
            StringValues value = default(StringValues);
            if (httpContext != null && httpContext.Request?.Headers?.TryGetValue("User-Agent", out value) == true)
            {
                return Detector.GetBrowser(value[0].AsSpan());
            }

            return null;
        }
    }

    internal static class Detector
    {
        internal static IBrowser? GetBrowser(ReadOnlySpan<char> userAgentString)
        {
            if (Firefox.TryParse(userAgentString, out var result))
            {
                return result;
            }

            if (EdgeChromium.TryParse(userAgentString, out var result2))
            {
                return result2;
            }

            if (InternetExplorer.TryParse(userAgentString, out var result3))
            {
                return result3;
            }

            if (Opera.TryParse(userAgentString, out var result4))
            {
                return result4;
            }

            if (Edge.TryParse(userAgentString, out var result5))
            {
                return result5;
            }

            if (Chrome.TryParse(userAgentString, out var result6))
            {
                return result6;
            }

            if (Safari.TryParse(userAgentString, out var result7))
            {
                return result7;
            }

            return null;
        }
    }

    internal class Firefox : Browser
    {
        public string Platform { get; }

        public override string Name => "Firefox";

        private Firefox(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out Firefox result)
        {
            string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "Firefox/");
            if (versionIfKeyPresent != null)
            {
                result = new Firefox(userAgent, versionIfKeyPresent);
                return true;
            }

            string versionIfKeyPresent2 = Browser.GetVersionIfKeyPresent(userAgent, "FxiOS/");
            if (versionIfKeyPresent2 != null)
            {
                result = new Firefox(userAgent, versionIfKeyPresent2);
                return true;
            }

            result = null;
            return false;
        }
    }

    internal class EdgeChromium : Browser
    {
        public override string Name => "EdgeChromium";

        public EdgeChromium(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out EdgeChromium result)
        {
            string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "Edg/");
            if (versionIfKeyPresent != null)
            {
                result = new EdgeChromium(userAgent, versionIfKeyPresent);
                return true;
            }

            result = null;
            return false;
        }
    }

    internal class InternetExplorer : Browser
    {
        public override string Name => "InternetExplorer";

        public InternetExplorer(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out InternetExplorer result)
        {
            string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "Trident/");
            if (versionIfKeyPresent != null)
            {
                result = new InternetExplorer(userAgent, versionIfKeyPresent);
                return true;
            }

            result = null;
            return false;
        }
    }

    internal class Opera : Browser
    {
        public override string Name => "Opera";

        public Opera(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out Opera result)
        {
            string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "OPR/");
            string versionIfKeyPresent2 = Browser.GetVersionIfKeyPresent(userAgent, " OPT/");
            if (versionIfKeyPresent != null)
            {
                result = new Opera(userAgent, versionIfKeyPresent);
                return true;
            }

            if (versionIfKeyPresent2 != null)
            {
                result = new Opera(userAgent, versionIfKeyPresent);
                return true;
            }

            result = null;
            return false;
        }
    }

    internal class Edge : Browser
    {
        public override string Name => "Edge";

        public Edge(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out Browser result)
        {
            object obj = Browser.GetVersionIfKeyPresent(userAgent, "Edge/");
            string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "EdgiOS/");
            string versionIfKeyPresent2 = Browser.GetVersionIfKeyPresent(userAgent, "EdgA/");
            if (obj == null)
            {
                obj = versionIfKeyPresent ?? versionIfKeyPresent2;
            }

            string text = (string)obj;
            if (text == null)
            {
                result = null;
                return false;
            }

            result = new Edge(userAgent, text);
            return true;
        }
    }

    internal class Chrome : Browser
    {
        public override string Name => "Chrome";

        public Chrome(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out Chrome result)
        {
            int num = userAgent.IndexOf("Chrome/".AsSpan());
            int num2 = userAgent.IndexOf("Safari/".AsSpan());
            int num3 = userAgent.IndexOf("CriOS/".AsSpan());
            if ((num2 > -1 && num > -1) || (num2 > -1 && num3 > -1))
            {
                string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "Chrome/");
                if (versionIfKeyPresent != null)
                {
                    result = new Chrome(userAgent, versionIfKeyPresent);
                    return true;
                }

                string versionIfKeyPresent2 = Browser.GetVersionIfKeyPresent(userAgent, "CriOS/");
                if (versionIfKeyPresent2 != null)
                {
                    result = new Chrome(userAgent, versionIfKeyPresent2);
                    return true;
                }
            }

            result = null;
            return false;
        }
    }

    internal class Safari : Browser
    {
        public override string Name => "Safari";

        public Safari(ReadOnlySpan<char> userAgent, string version)
            : base(userAgent, version)
        {
        }

        public static bool TryParse(ReadOnlySpan<char> userAgent, out Safari result)
        {
            int num = userAgent.IndexOf("Chrome/".AsSpan());
            if (userAgent.IndexOf("Safari/".AsSpan()) > -1 && num == -1)
            {
                string versionIfKeyPresent = Browser.GetVersionIfKeyPresent(userAgent, "Safari/");
                if (versionIfKeyPresent != null)
                {
                    result = new Safari(userAgent, versionIfKeyPresent);
                    return true;
                }
            }

            result = null;
            return false;
        }
    }

    internal abstract class Browser : IBrowser
    {
        private readonly string platform;

        public abstract string Name { get; }

        public string DeviceType { get; }

        public string Version { get; }

        public string OS { get; }

        protected Browser(ReadOnlySpan<char> userAgent, string version)
        {
            Version = version;
            (string, string, bool) platformAndOS = PlatformDetector.GetPlatformAndOS(userAgent);
            platform = platformAndOS.Item1;
            OS = platformAndOS.Item2;
            DeviceType = GetDeviceType(platformAndOS);
        }

        protected static string GetVersionIfKeyPresent(ReadOnlySpan<char> userAgent, string key)
        {
            int num = userAgent.IndexOf(key.AsSpan());
            if (num == -1)
            {
                return null;
            }

            ReadOnlySpan<char> span = userAgent.Slice(num + key.Length);
            int num2 = span.IndexOf(' ');
            if (num2 > -1)
            {
                return span.Slice(0, num2).ToString();
            }

            return span.ToString();
        }

        private string GetDeviceType((string Platform, string OS, bool MobileDetected) platform)
        {
            if (this.platform == "iPhone")
            {
                return "Mobile";
            }

            if (this.platform == "iPad" || this.platform == "GalaxyTabS4")
            {
                return "Tablet";
            }

            if (platform.MobileDetected)
            {
                return "Mobile";
            }

            if (this.platform == "Macintosh" || this.platform.StartsWith("Windows NT"))
            {
                return "Desktop";
            }

            if (this.platform == "Linux" && platform.OS == "Android" && !platform.MobileDetected)
            {
                return "Tablet";
            }

            return string.Empty;
        }
    }

    public interface IBrowserDetector
    {
        IBrowser? Browser { get; }
    }

    public interface IBrowser
    {
        string DeviceType { get; }

        string Name { get; }

        string OS { get; }

        string Version { get; }
    }
}